package cvut.fit.dpo.pr2;

import java.util.Stack;

import cvut.fit.dpo.arithmetic.AddOperator;
import cvut.fit.dpo.arithmetic.ArithmeticExpression;
import cvut.fit.dpo.arithmetic.BinaryOperator;
import cvut.fit.dpo.arithmetic.NumericOperand;
import cvut.fit.dpo.arithmetic.SubstractOperator;

/**
 * Stupid class which can create some {@link ArithmeticExpression}s.
 * 
 * @author Jan Kurš
 * 
 */
public class ArithmeticExpressionCreator {
	/**
	 * Creates 3 - (1 + 2)
	 * 
	 * This is ugly. I don't like creating expressions in this form. I never know, what expression I have created...
	 */
	public ArithmeticExpression createExpression1() {

		final NumericOperand op1 = new NumericOperand(3);
		final NumericOperand op2 = new NumericOperand(1);
		final NumericOperand op3 = new NumericOperand(2);
        
		final BinaryOperator o2 = new AddOperator(op2, op3);
		final BinaryOperator o1 = new SubstractOperator(op1, o2);
		return o1;
	}

	/**
	 * Creates (3 - 1) + 2
	 * 
	 * This is ugly. I don't like creating expressions in this form. I never know, what expression I have created...
	 */
	public ArithmeticExpression createExpression2() {

		final NumericOperand op1 = new NumericOperand(1);
		final NumericOperand op2 = new NumericOperand(2);
		final NumericOperand op3 = new NumericOperand(3);
         
		final BinaryOperator o1 = new SubstractOperator(op3, op1);
		final BinaryOperator o2 = new AddOperator(o1, op2);
		return o2;
	}

	/**
	 * Creates any expression from the RPN input. This is nice and universal.
	 * 
	 * @see http://en.wikipedia.org/wiki/Reverse_Polish_notation
	 * 
	 * @param input
	 *            in Reverse Polish Notation
	 * @return {@link ArithmeticExpression} equivalent to the RPN input.
	 */
	public ArithmeticExpression createExpressionFromRPN(final String input) {
		final Stack<ArithmeticExpression> stack = new Stack<ArithmeticExpression>();

		final String[] splits = input.split(" ");
		for (String element : splits) {
			final ArithmeticExpression arithmeticExpression;
			if ("-".equals(element)) {
				final ArithmeticExpression right = stack.pop();
				final ArithmeticExpression left = stack.pop();
				arithmeticExpression = new SubstractOperator(left, right);
			} else if ("+".equals(element)) {
				final ArithmeticExpression secondO = stack.pop();
				final ArithmeticExpression firstO = stack.pop();
				arithmeticExpression = new AddOperator(firstO, secondO);
			} else {
				arithmeticExpression = new NumericOperand(Integer.parseInt(element));
			}
			stack.push(arithmeticExpression);
		}
		return stack.pop();
	}
}
